package br.com.android.financas.repositorio.impl;

import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.PeriodType;

import android.content.Context;
import br.com.android.financas.MesTotal;
import br.com.android.financas.model.Apresentavel;
import br.com.android.financas.model.Receita;
import br.com.android.financas.repositorio.RepositorioGenerico;
import br.com.android.financas.repositorio.RepositorioReceita;

import com.j256.ormlite.dao.ForeignCollection;
import com.j256.ormlite.dao.GenericRawResults;

public class RepositorioReceitaImpl extends RepositorioGenerico<Receita> implements RepositorioReceita {

	public RepositorioReceitaImpl(Context context) throws SQLException {
		super(context);
	}

	private double getTotal(List<Receita> receitas){
		double total=0;
		for(Receita receita:receitas){
			total+=receita.getValor();
		}
		return total;
	}

	public double getTotal() {

		double total=0;
		try {
			total = getDatabase().queryRawValue("select sum(valor) from receita");
		} catch (Exception e) {
			total=0;
		}

		return total;
	}

	@Override
	public double getTotal(Date mes) {

		DateTime m=new DateTime(mes.getTime());

		DateTime ini=m.dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
		DateTime fim=m.dayOfMonth().withMaximumValue().withTimeAtStartOfDay();


		return getTotal(ini.toDate(), fim.toDate());
	}

	@Override
	public double getTotal(Date ini, Date fim) {

		try {

			GenericRawResults<String[]> rawResults= getDatabase().queryRaw("select sum(valor) from receita where date(data/1000,'unixepoch','localtime')  between ? and ?", new SimpleDateFormat("yyyy-MM-dd").format(ini)  ,new SimpleDateFormat("yyyy-MM-dd").format(fim));
			return Double.parseDouble(rawResults.getFirstResult()[0]);

		} catch (Exception e) {
			return 0;
		}
	}

	@Override
	public Map<DateTime, Double> getReceitasMensais(Date ini, Date fim) {

		Map<DateTime,Double> Receitas= new LinkedHashMap<DateTime, Double>();

		Period p= new Period(ini.getTime(),fim.getTime());
		int qtd=p.getMonths();

		for(int i=0;i<=qtd;i++){
			DateTime d=(new DateTime(ini.getTime())).plusMonths(i);

			double total=getTotal(d.toDate());

			Receitas.put(d, total);

		}

		return Receitas;
	}

	@Override
	public Map<MesTotal, List<Apresentavel>> getReceitasMensais() {
		Map<MesTotal, List<Apresentavel>> meses=new LinkedHashMap<MesTotal, List<Apresentavel>>();
		List<Receita> Receitas=listar();

		Map<DateTime,MesTotal> mesesIncluidos=new HashMap<DateTime,MesTotal>();

		for(Receita Receita:Receitas){

			DateTime tMes= (new DateTime(Receita.getData().getTime())).dayOfMonth().withMinimumValue().withTimeAtStartOfDay();

			if(!mesesIncluidos.containsKey(tMes)){
				MesTotal mes= new MesTotal();
				mes.setMes(tMes);
				mes.setTotal(getTotal(tMes.toDate()));

				mesesIncluidos.put(tMes, mes);
				meses.put(mes, new ArrayList<Apresentavel>());
			}

			meses.get(mesesIncluidos.get(tMes)).add(Receita);

		}

		return meses;
	}


	@Override
	public void excluir(Receita receita, Date aPartir) throws SQLException {
		List<Receita> receitas;
		if (!receita.isPai()) {
			ForeignCollection<Receita> t = receita.getPai().getFilhos();
			receitas = new ArrayList<Receita>();
			receitas.addAll(t);
			receitas.remove(receita);
		} else {
			ForeignCollection<Receita> t = receita.getFilhos();
			receitas = new ArrayList<Receita>();
			receitas.addAll(t);
		}

		DateTime ini = new DateTime(aPartir.getTime());

		for (Receita d : receitas) {
			DateTime mes = new DateTime(d.getData().getTime());

			if (mes.isAfter(ini))
				excluir(d);
		}
		excluir(receita);

	}

	@Override
	public void excluir(Receita receita, boolean todos) throws SQLException {
		List<Receita> receitas;
		if (!receita.isPai()) {
			receitas = listarPorAtributo("pai", receita.getPai());
			receitas.remove(receita);
		} else {
			ForeignCollection<Receita> t = receita.getFilhos();
			receitas = new ArrayList<Receita>();
			receitas.addAll(t);
		}

		for (Receita d : receitas) {
			excluir(d);
		}
		excluir(receita);
	}


	@Override
	public void atualizarGrupo(Receita receita) throws SQLException {
		Receita pai;
		List<Receita> receitas;
		if (!receita.isPai()) {
			pai=receita.getPai();
		} else {
			pai=receita;
		}
		receitas=new ArrayList<Receita>(pai.getFilhos());

		String descricao=pai.getDescricao();
		descricao=descricao.replaceAll("\\d+\\/\\d+", "");
		descricao.trim();
		DateTime ini = new DateTime(pai.getData().getTime());
		double valor = receita.getValor();
		int i=1;
		int qtd=receitas.size()+1;

		for (Receita d : receitas) {
			d.setValor(valor);
			d.setDescricao(descricao);
			d.setData( ini.plusMonths(i).toDate());
			atualizar(d);
			i++;
		}

		pai.setDescricao(descricao);
		atualizar(pai);
	}

	@Override
	public void atualizarGrupo(Receita receita, Date aPartir)
			throws SQLException {

		if(receita.isPai())
			atualizarGrupo(receita);
		else{
			List<Receita> receitas=	getDatabase().queryBuilder().orderBy("data", true).where().eq("pai_id", receita.getPai()).and().gt("data", receita.getData()).query();

			DateTime ini = new DateTime(receita.getPai().getData().getTime());
			DateTime fim = new DateTime(receita.getData().getTime());

			Period p = new Period(ini, fim, PeriodType.months().withDaysRemoved());
			//int descCount = p.getMonths()+1;
			//int qtd=receita.getPai().getFilhos().size()+1;
			int i= 1;

			String descricao=receita.getDescricao();
			//descricao=descricao.replaceAll("\\d+\\/\\d+", "");
			//descricao.trim();
			double valor = receita.getValor();
			for(Receita d:receitas){
				d.setDescricao(descricao);
				d.setValor(valor);
				d.setData( fim.plusMonths(i).toDate());
				atualizar(d);
				i++;
				//descCount++;
			}
			atualizar(receita);

		}
	}

	@Override
	public List<MesTotal> getTotaisMensais() {

		try {
			List<MesTotal> totais=new ArrayList<MesTotal>();
			GenericRawResults<String[]> rawResults= getDatabase().queryRaw("select date(data/1000,'unixepoch','localtime'),sum(valor) from receita group by strftime('%Y-%m',date(data/1000,'unixepoch','localtime'))");

			for (String[] resultArray : rawResults) {
				MesTotal mes= new MesTotal();
				try {
					DateTime data=new DateTime( new SimpleDateFormat("yyyy-MM-dd").parse(resultArray[0].split("\\.")[0]).getTime());
					data=data.dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
					mes.setMes(data);
					mes.setTotal(Double.parseDouble(resultArray[1]) );
					totais.add(mes);
				} catch (ParseException e) {
					e.printStackTrace();
				}
			}
			rawResults.close();
			return totais;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return Collections.emptyList();
	}

	@Override
	public List<Receita> getReceitas(Date mes) {
		DateTime m = new DateTime(mes.getTime());

		DateTime ini = m.dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
		DateTime fim = m.dayOfMonth().withMaximumValue().withTimeAtStartOfDay();

		return getReceitas(ini.toDate(), fim.toDate());
	}

	@Override
	public List<Receita> getReceitas(Date ini, Date fim) {

		try {
			return  getDatabase().queryBuilder().where().between("data", ini, fim).or().eq("data", ini).or().eq("data", fim).query();
		} catch (SQLException e1) {}
		return Collections.emptyList();
	}

}
